package com.yunwaikeji.gy_tool_library.utils.http;

import android.text.TextUtils;

import com.google.gson.Gson;
import com.yunwaikeji.gy_tool_library.info.GYHttpInfo;
import com.yunwaikeji.gy_tool_library.task.GYAsyncTask;
import com.yunwaikeji.gy_tool_library.utils.GYLogUtils;
import com.yunwaikeji.gy_tool_library.utils.GYUiUtils;

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class GYHttpAsyncTask<Task extends GYHttpAsyncTask<Task, ?>, Model extends GYHttpModel<?>> extends GYAsyncTask<Task, Object, Object, Object> implements GYHttpInfo {
    private Model httpModel;
    private GYHttpListener<HttpURLConnection> httpListener;//监听
    private HttpURLConnection httpURLConnection;
    private final Gson gson = new Gson();
    private String headersPrint;
    private boolean responseMainThread = true;//回调是否在主线程运行

    public void printRequestLog(String url, String headers, String msg) {
        GYLogUtils.printJson("gylibrary网络框架", "请求\n" + url + "\nHeaders:" + headers, msg);
    }

    private void printRequestLog(String url, String headers) {
        printRequestLog(url, headers, "");
    }

    private void printRequestLog(String url) {
        printRequestLog(url, "");
    }

    private void printResponseLog(String url, String msg) {
        GYLogUtils.printJson("gylibrary网络框架", "响应\n" + url, msg);
    }

    public Model getHttpModel() {
        return httpModel;
    }

    public Task setHttpModel(Model httpModel) {
        this.httpModel = httpModel;
        return getTask();
    }

    public Task setHttpListener(GYHttpListener<HttpURLConnection> httpListener) {
        this.httpListener = httpListener;
        setTaskListener(this.httpListener);
        return getTask();
    }

    private HttpURLConnectionResult httpURLConnectionResult;

    public interface HttpURLConnectionResult {
        HttpURLConnection httpURLConnection(HttpURLConnection httpURLConnection);
    }

    public Task setHttpURLConnectionResult(HttpURLConnectionResult httpURLConnectionResult) {
        this.httpURLConnectionResult = httpURLConnectionResult;
        return getTask();
    }

    @Override
    public Integer start() {
        if (httpModel == null) {
            onError("请初始化请求参数");
            return getTagId();
        }
        if (!TextUtils.isEmpty(requestMethod)) {
            httpModel.setRequestMethod(requestMethod);
            requestMethod = null;
        }
        if (TextUtils.isEmpty(httpModel.getRequestMethod())) {
            onError("请设置请求方式requestMethod");
            return getTagId();
        }
        if (TextUtils.isEmpty(httpModel.getUrl())) {
            onError("url不能为空");
            return getTagId();
        }
        return super.start();
    }

    @Override
    public void onLoading(long nowBytes, long totalBytes, long secondBytes) {

    }

    @Override
    public void onSuccess(Object response) {
        if (responseMainThread) {
            GYUiUtils.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    httpListener.success((HttpURLConnection) response);
                }
            });
        } else {
            httpListener.success((HttpURLConnection) response);
        }
    }

    private String requestMethod;

    public Integer startGet() {
        requestMethod = RequestMethod.GET;
        return start();
    }

    public Integer startPost() {
        requestMethod = RequestMethod.POST;
        return start();
    }

    public Integer startPut() {
        requestMethod = RequestMethod.PUT;
        return start();
    }

    public Integer startDelete() {
        requestMethod = RequestMethod.DELETE;
        return start();
    }

    // 方法1：onPreExecute（）
    // 作用：执行 线程任务前的操作
    // 注：根据需求复写
    @Override
    protected void onPreExecute() {
        if (httpListener != null) {
            httpListener.start();
        }
        super.onPreExecute();
    }

    // 方法2：doInBackground（）
    // 作用：接收输入参数、执行任务中的耗时操作、返回 线程任务执行的结果
    // 注：必须复写，从而自定义线程任务
    @Override
    protected Object doInBackground() {
        headersPrint = gson.toJson(httpModel.getHeaders());
        switch (httpModel.getDataType()) {
            case QUERY:
                startQuery();
                break;
            case BODY:
                startBody();
                break;
        }
        return getTagId();
    }

    // 方法3：onProgressUpdate（）
    // 作用：在主线程 显示线程任务执行的进度
    // 注：根据需求复写
    @Override
    protected void onProgressUpdate(Object... values) {
        super.onProgressUpdate(values);
    }

    // 方法4：onPostExecute（）
    // 作用：接收线程任务执行结果、将执行结果显示到UI组件
    // 注：必须复写，从而自定义UI操作
    @Override
    protected void onPostExecute(Object object) {
        super.onPostExecute(object);
        if (httpListener != null) {
//            if (response != null) {
//                httpListener.success(response);
//            }
            httpListener.finish();
        }
    }

    // 方法5：onCancelled()
    // 作用：将异步任务设置为：取消状态
    @Override
    protected void onCancelled() {
        super.onCancelled();
        if (httpURLConnection != null) {
            httpURLConnection.disconnect();
        }
        if (httpListener != null) {
            httpListener.finish();
        }
    }

    public Task setResponseMainThread(boolean responseMainThread) {
        this.responseMainThread = responseMainThread;
        return getTask();
    }

    public boolean isResponseMainThread() {
        return responseMainThread;
    }

    private void startQuery() {
        StringBuilder querySb = new StringBuilder();
        try {
            URL url = new URL(httpModel.getUrl());
            httpURLConnection = (HttpURLConnection) url.openConnection();
            // 输入 输出 都打开
//            httpURLConnection.setDoOutput(true);
//            httpURLConnection.setDoInput(true);
            for (String key : httpModel.getHeaders().keySet()) {
                httpURLConnection.addRequestProperty(key, String.valueOf(httpModel.getHeaders().get(key)));
            }
            for (String key : httpModel.getParams().keySet()) {
                if (TextUtils.isEmpty(querySb)) {
                    querySb.append("?");
                } else {
                    querySb.append("&");
                }
                querySb.append(key).append("=").append(httpModel.getParams().get(key));
                httpURLConnection.addRequestProperty(key, String.valueOf(httpModel.getParams().get(key)));
            }
            printRequestLog(httpModel.getUrl() + querySb, headersPrint);

            httpURLConnection.setRequestMethod(httpModel.getRequestMethod());
//            httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
            // 输入 输出 都打开
//            httpURLConnection.setDoOutput(true);
//            httpURLConnection.setDoInput(true);

            if (httpURLConnectionResult == null) {
                httpURLConnection.connect();
            } else {
                httpURLConnection = httpURLConnectionResult.httpURLConnection(httpURLConnection);
            }
            // 获取响应流
            if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                onSuccess(httpURLConnection);
            } else {
                onError(httpURLConnection.getResponseMessage());
                httpURLConnection.disconnect();
            }
        } catch (Exception e) {
            e.printStackTrace();
            printResponseLog(httpModel.getUrl() + querySb, e.toString());
            onError(e.toString());
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
//                if (httpURLConnection != null) {
//                    httpURLConnection.disconnect();
//                }
            } catch (Exception e) {
                e.printStackTrace();
                onError(e.toString());
            }
        }
    }

    private OutputStream out;

    private void startBody() {
//        response = null;
        try {
            URL url = new URL(httpModel.getUrl());
            httpURLConnection = (HttpURLConnection) url.openConnection();
            for (String key : httpModel.getHeaders().keySet()) {
                httpURLConnection.addRequestProperty(key, String.valueOf(httpModel.getHeaders().get(key)));
            }
            printRequestLog(httpModel.getUrl(), headersPrint);
            httpURLConnection.setRequestProperty("Content-Type", "application/json");
            // 输入 输出 都打开
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setDoInput(true);

            httpURLConnection.setRequestMethod(httpModel.getRequestMethod());

            if (httpURLConnectionResult == null) {
                httpURLConnection.connect();
            } else {
                httpURLConnection = httpURLConnectionResult.httpURLConnection(httpURLConnection);
            }

            // 传递参数  流的方式
            out = httpURLConnection.getOutputStream();
            out.write(gson.toJson(httpModel.getParams()).getBytes());
            out.flush();

            // 获取响应流
            if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                onSuccess(httpURLConnection);
            } else {
                onError(httpURLConnection.getResponseMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
            printResponseLog(httpModel.getUrl(), e.toString());
            onError(e.toString());
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (httpURLConnection != null) {
                    httpURLConnection.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
                onError(e.toString());
            }
        }
    }

    @Override
    public void onError(String error) {
        super.onError(error);
        if (!isStarting() && httpListener != null) {
            if (isResponseMainThread()) {
                GYUiUtils.runOnUiThread(() -> httpListener.finish());
            } else {
                httpListener.finish();
            }
        }
    }
}
